<!DOCTYPE html>
<html>
  <head>
    <title>Collection Demo</title>
    <script src="../src/traceur.js"></script>
    <script src="../src/bootstrap.js"></script>
  </head>
  <body>
    <p>This example shows how to use element set/get/delete meta operations.

    <pre id="out"></pre>

    <script type="text/traceur">

      function print(s) {
        var out = document.getElementById('out');
        out.appendChild(document.createTextNode(`$s\n`));
      }

      function assertEquals(expected, actual) {
        if (expected === actual)
          print(`PASS: $actual`);
        else
          print(`FAIL: Expected $expected, got $actual`);
      }

      function StringMap() {
        Object.defineProperty(this, '_storage', {value: Object.create(null)});
        Object.defineProperty(this, '_size', {value: 0, writable: true});
      }

      StringMap.prototype = {
        get size() {
          return this._size;
        }
        has(name) {
          return name in this._storage;
        }
        keys() {
          var storage = this._storage;
          return (function* () {
            for (var name in storage) {
              yield name;
            }
          })();
        }
        values() {
          var storage = this._storage;
          return (function* () {
            for (var name in storage) {
              yield storage[name];
            }
          })();
        }
        items() {
          var storage = this._storage;
          return (function* () {
            for (var name in storage) {
              yield [name, storage[name]];
            }
          })();
        }
      };

      var Name = traceur.runtime.modules['@name'];
      var {elementGet, elementSet, elementDelete} = Name;

      StringMap.prototype[elementGet] = function(name) {
        return this._storage[name];
      };

      StringMap.prototype[elementDelete] = function(name) {
        if (!this.has(name))
          return false;
        delete this._storage[name];
        this._size--;
        return true;
      };

      StringMap.prototype[elementSet] = function(name, value) {
        if (!this.has(name))
          this._size++;
        this._storage[name] = value;
      };

      var map = new StringMap;
      map['a'] = 1;
      assertEquals(1, map['a']);
      assertEquals(undefined, map.a);
      assertEquals(1, map.size);
      map['b'] = 2;
      assertEquals(2, map['b']);
      assertEquals(2, map.size);

      assertEquals(false, map.has('size'));
      map['size'] = 'Hello World';
      assertEquals('Hello World', map['size']);
      assertEquals(3, map.size);

      delete map['b'];
      assertEquals(undefined, map['b']);
      assertEquals(2, map.size);

      print('\nTesting iteration');

      for (var key of map.keys()) {
        print(key);
      }

      for (var value of map.values()) {
        print(value);
      }

      // for (var [name, value] of map.items()) {
      // http://code.google.com/p/traceur-compiler/issues/detail?id=42
      for (var item of map.items()) {
        var [key, value] = item;
        print(`$key = $value`);
      }

    </script>
  </body>
</html>
